﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
#if !SILVERLIGHT
using System.ComponentModel.Design.Serialization;
#endif
using System.Globalization;
using System.Reflection;
using UIT.Style;

namespace UIT.Converters
{
    /// <summary>
    ///     Converts from a <see cref="T:System.Web.UI.WebControls.Unit" /> object to an object of another data type and from another type to a <see cref="T:System.Web.UI.WebControls.Unit" /> object.
    /// </summary>
    public class UnitConverter : TypeConverter
    {
        /// <summary>
        ///     Returns a value indicating whether the unit converter can convert from the specified source type.
        /// </summary>
        /// <returns>true if the source type can be converted from; otherwise, false.
        /// </returns>
        /// <param name="context">
        ///     An <see cref="T:System.ComponentModel.ITypeDescriptorContext" /> instance that specifies the context of the object to convert. 
        /// </param>
        /// <param name="sourceType">
        ///     The type of the source. 
        /// </param>
        public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
        {
            return sourceType == typeof(string) || base.CanConvertFrom(context, sourceType);
        }
        /// <summary>
        ///     Returns a value indicating whether the converter can convert a <see cref="T:System.Web.UI.WebControls.Unit" /> object to the specified type.
        /// </summary>
        /// <returns>true if the converter supports converting a <see cref="T:System.Web.UI.WebControls.Unit" /> object to the destination type; otherwise, false.
        /// </returns>
        /// <param name="context">
        ///     An <see cref="T:System.ComponentModel.ITypeDescriptorContext" /> that indicates the context of the object to convert.
        /// </param>
        /// <param name="destinationType">
        ///     The <see cref="T:System.Type" /> that represents the data type to convert to.
        /// </param>
        public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
        {
#if !SILVERLIGHT
            return destinationType == typeof(string) || destinationType == typeof(double) || destinationType == typeof(InstanceDescriptor) || base.CanConvertTo(context, destinationType);
#else
            return destinationType == typeof(string) || destinationType == typeof(double) || base.CanConvertTo(context, destinationType);
#endif
        }
        /// <summary>
        ///     Performs type conversion from the specified context, object, and argument list.
        /// </summary>
        /// <returns>
        ///     The object resulting from conversion.
        /// </returns>
        /// <param name="context">
        ///     An <see cref="T:System.ComponentModel.ITypeDescriptorContext" /> instance that indicates the context of the object to convert. 
        /// </param>
        /// <param name="culture">
        ///     A <see cref="T:System.Globalization.CultureInfo" /> object that represents information about a culture such as language, calendar system, and so on. This parameter is not used in this method. It is reserved for future versions of this method. You can optionally pass null for this parameter. 
        /// </param>
        /// <param name="value">
        ///     The object to convert. 
        /// </param>
        public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
        {
            if (value == null)
            {
                return null;
            }
            string text = value as string;
            if (text == null)
            {
                return base.ConvertFrom(context, culture, value);
            }
            return FromString(text, culture);
        }
        /// <summary>
        ///     Performs type conversion to the specified destination type given the specified context, object and argument list.
        /// </summary>
        /// <returns>
        ///     The object resulting from conversion.
        /// </returns>
        /// <param name="context">
        ///     An <see cref="T:System.ComponentModel.ITypeDescriptorContext" /> instance that indicates the context of the object to convert. 
        /// </param>
        /// <param name="culture">
        ///     A <see cref="T:System.Globalization.CultureInfo" /> object that represents information about a culture such as language, calendar system, and so on. This parameter is not used in this method. It is reserved for future versions of this method. You can optionally pass null for this parameter. 
        /// </param>
        /// <param name="value">
        ///     The object to convert. 
        /// </param>
        /// <param name="destinationType">
        ///     The type to convert to. 
        /// </param>
        public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
        {
            if (destinationType == typeof(string))
            {
                if (value == null || ((Unit)value).IsEmpty)
                {
                    return null;
                }
                return ((Unit)value).ToString(culture);
            }
            else if (destinationType == typeof(double))
            {
                if (((Unit)value).IsEmpty)
                    return double.NaN;
                return ((Unit)value).Value;
            }
            else
            {
#if !SILVERLIGHT
                if (destinationType != typeof(InstanceDescriptor) || value == null)
                {
#endif
                return base.ConvertTo(context, culture, value, destinationType);
#if !SILVERLIGHT
                }

                Unit unit = (Unit)value;
                MemberInfo memberInfo = null;
                object[] arguments = null;
                if (unit.IsEmpty)
                {
                    memberInfo = typeof(Unit).GetField("Empty");
                }
                else
                {
                    memberInfo = typeof(Unit).GetConstructor(new Type[]
                    {
                        typeof(double), 
                        typeof(UnitType)
                    });
                    arguments = new object[]
                    {
                        unit.Value, 
                        unit.Type
                    };
                }
                if (memberInfo != null)
                {
                    return new InstanceDescriptor(memberInfo, arguments);
                }
                return null;
#endif
            }
        }

        public static Unit FromString(string text, CultureInfo culture)
        {
            string text2 = text.Trim();
            if (text2.Length == 0)
            {
                return Unit.Empty;
            }
            if (culture != null)
            {
                return Unit.Parse(text2, culture);
            }
            return Unit.Parse(text2, CultureInfo.CurrentCulture);
        }
    }
}
